iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
Security

「站住 口令 誰」關於資安權限與授權的觀念教學,以Spring boot Security框架實作系列 第 28

Day 28:專案案例 Part 2 — 加入授權邏輯 (RBAC + ABAC)

  • 分享至 

  • xImage
  •  

在昨天(Day 27)我們完成了 JWT + OIDC 的整合,今天進一步加入 授權邏輯

想要看完整Code的朋友可以參考以下的連結,我把所有的程式碼都放在這裡,依照Branch分類

https://github.com/AnsathSean/spring-security-30days.git

因為只剩下幾天了,我們在今天會同時示範兩種授權模型:

  1. RBAC(Role-Based Access Control)
    • 基於角色的存取控制。
    • 例如:只有 ROLE_ADMIN 才能進入管理員專區。
  2. ABAC(Attribute-Based Access Control)
    • 基於屬性的存取控制。
    • 例如:只有「HR 部門」的員工才能存取 HR API。

一、程式碼架構

今天的專案主要包含以下部分:

  • AuthController:定義不同角色與部門的 API。
  • JwtAuthenticationFilter:驗證 JWT 並建立 Authentication。
  • JwtUtil:生成與驗證 Token。
  • SecurityConfig:整合 JWT + OIDC + Method Security。
  • DepartmentSecurity(自訂 Bean,支援 ABAC 判斷,文章會補充)。

二、RBAC — 基於角色的授權

程式碼

//  RBAC: 只有 ADMIN 才能進
@GetMapping("/admin")
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public String adminOnly() {
    return "這是管理員專區 (RBAC)";
}

//  RBAC: 只有 USER 才能進
@GetMapping("/user")
@PreAuthorize("hasAuthority('ROLE_USER')")
public String userOnly() {
    return "這是一般使用者專區 (RBAC)";
}

說明

  • 使用 @PreAuthorize 搭配 SpEL(Spring Expression Language)。
  • hasAuthority('ROLE_ADMIN') 會檢查目前登入的使用者是否擁有該權限。
  • 在登入時,JWT 已經把 role 存進去了,所以能對應到這裡的判斷。

三、ABAC — 基於屬性的授權

程式碼

//  ABAC: 只有部門=HR 才能進
@GetMapping("/department/hr")
@PreAuthorize("@departmentSecurity.checkDepartment(authentication, 'HR')")
public String hrDepartment() {
    return "這是 HR 部門專區 (ABAC)";
}

//  ABAC: 只有部門=IT 才能進
@GetMapping("/department/it")
@PreAuthorize("@departmentSecurity.checkDepartment(authentication, 'IT')")
public String itDepartment() {
    return "這是 IT 部門專區 (ABAC)";
}

說明

  • 這裡的 @departmentSecurity 是一個自訂的 Spring Bean,用來檢查使用者是否屬於特定部門。
  • authentication 代表目前登入使用者的上下文,包含使用者名稱與權限。
  • checkDepartment 方法會讀取使用者屬性,判斷是否符合條件(例如:部門 = HR)。

範例實作 — DepartmentSecurity

package com.ansathsean.security;

import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

@Component("departmentSecurity")
public class DepartmentSecurity {

    public boolean checkDepartment(Authentication authentication, String requiredDepartment) {
        // 假設我們未來會從 DB 或 OIDC Claim 中查詢部門資訊
        String username = authentication.getName();

        // Demo 模擬:不同帳號對應不同部門
        if ("admin".equals(username) && "HR".equals(requiredDepartment)) {
            return true;
        } else if ("user".equals(username) && "IT".equals(requiredDepartment)) {
            return true;
        }
        return false;
    }
}

這樣一來,就能在程式中 依照部門屬性 來限制 API 存取。

四、SecurityConfig — 啟用方法層級授權

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .formLogin(form -> form.disable())
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/api/login", "/login-with-refresh").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2Login(withDefaults()) //  OIDC
            .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); //  JWT

        return http.build();
    }
}

關鍵點

  • @EnableMethodSecurity → 開啟 @PreAuthorize 註解功能。
  • .anyRequest().authenticated() → 其他路徑一律需要授權。

五、驗證流程測試

我們這裡已經整合了JWT,所以一開始不免俗地就要先測試JWT

1. JWT 登入

Post 這個APIhttp://localhost:8080/api/login

在Body中選擇Raw,輸入以下資訊


{ "username": "admin", "password": "password" }

Send之後回傳:

{ "accessToken": "eyJhbGciOi..." }

https://ithelp.ithome.com.tw/upload/images/20251007/20152864MlbPq9DgzF.png

2. RBAC 測試

http://localhost:8080/admin


Authorization: Bearer <admin_token>

https://ithelp.ithome.com.tw/upload/images/20251007/20152864AKRdGHKfT8.png

admin 可存取,user 被拒絕。

https://ithelp.ithome.com.tw/upload/images/20251007/20152864XzsKV90YUb.png

https://ithelp.ithome.com.tw/upload/images/20251007/20152864SgTnyA0USR.png

3. ABAC 測試

我們繼續用admin取得token,然後測試以下的連結

Get http://localhost:8080/department/hr

admin 屬於 HR → 通過。

https://ithelp.ithome.com.tw/upload/images/20251007/20152864ujriPVWpfl.png

Get http://localhost:8080 /department/it

user 屬於 IT → 通過。

https://ithelp.ithome.com.tw/upload/images/20251007/20152864QMPwfAIM0U.png


六、結語與下一步

今天我們完成了 RBAC + ABAC 的整合

  • RBAC:簡單直觀,透過角色控管。
  • ABAC:更精細,透過屬性(如部門)控制資源。

這樣的設計讓系統更接近真實業務邏輯,可以同時滿足「基於職位」與「基於條件」的需求。

那麼今天的分享就到這裡,那我們明天見!


上一篇
Day 27:專案案例 Part 1 — 整合 JWT + OIDC
下一篇
Day 29:專案案例 Part 3 — 進階授權策略與最佳實務
系列文
「站住 口令 誰」關於資安權限與授權的觀念教學,以Spring boot Security框架實作30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言